package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.constants.RedisConstants;
import com.tianji.learning.entity.PointsRecord;
import com.tianji.learning.enums.PointsRecordType;
import com.tianji.learning.mapper.PointsRecordMapper;
import com.tianji.learning.mq.msg.SignInMessage;
import com.tianji.learning.service.PointsRecordService;
import com.tianji.learning.vo.PointsStatisticsVO;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author 墨墨
 * @description 针对表【points_record(学习积分记录，每个月底清零)】的数据库操作Service实现
 * @createDate 2024-10-30 11:30:57
 */
@Service
@RequiredArgsConstructor
public class PointsRecordServiceImpl extends ServiceImpl<PointsRecordMapper, PointsRecord>
        implements PointsRecordService {

    private final StringRedisTemplate redisTemplate;

    @Override
    public void addPointReord(SignInMessage msg, PointsRecordType type) {
        // 0.校验
        if (msg.getUserId() == null || msg.getPoints() == null) {
            return;
        }

        int realPoints = msg.getPoints(); //实际可以增加的积分

        // 1.判断该类型是否有积分上限
        int maxPoints = type.getMaxPoints();
        if (maxPoints > 0) {
            LocalDateTime now = LocalDateTime.now();
            LocalDateTime dayStartTime = DateUtils.getDayStartTime(now);
            LocalDateTime dayEndTime = DateUtils.getDayEndTime(now);
            // 2.如果有上限  查询该用户 该类型积分 是否超过上限 points_reord
            QueryWrapper<PointsRecord> wrapper = new QueryWrapper<>();
            wrapper.select("sum(points) as totalPoints");
            wrapper.eq("user_id", msg.getUserId());
            wrapper.eq("type", type);
            wrapper.between("create_time", dayStartTime, dayEndTime);
            Map<String, Object> map = this.getMap(wrapper);
            int currentPoints = 0; //当前用户 该积分类型的总积分
            if (map != null) {
                BigDecimal totalPoints = (BigDecimal) map.get("totalPoints");
                int i = totalPoints.intValue();
            }
            // 3.判断记录是否超过上限
            if (currentPoints >= maxPoints) {
                // 说明积分已经超过上限
                return;
            }
            // 本次实际应该加的积分
            if (currentPoints + realPoints > maxPoints) {
                realPoints = maxPoints - currentPoints;
            }
        }
        // 4.保存积分
        PointsRecord record = new PointsRecord();
        record.setUserId(msg.getUserId());
        record.setType(type);
        record.setPoints(realPoints);
        this.save(record);

        // 5.累加并保存总积分到redis 采用zset  当前赛季的排行榜
        LocalDate now = LocalDate.now();
        String format = now.format(DateTimeFormatter.ofPattern("yyyyMM"));
        String key = RedisConstants.POINTS_BOARD_KEY_PREFIX + format;
        redisTemplate.opsForZSet().incrementScore(key, msg.getUserId().toString(), realPoints);
    }

    @Override
    public List<PointsStatisticsVO> queryMyTodayPoints() {
        // 1.获取用户id
        Long userId = UserContext.getUser();

        // 2.查询积分表points_record 条件：user_id, 今日，按type分组
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime dayStartTime = DateUtils.getDayStartTime(now);
        LocalDateTime dayEndTime = DateUtils.getDayEndTime(now);
        QueryWrapper<PointsRecord> wrapper = new QueryWrapper<>();
        wrapper.select("type, sum(points) as points");
        wrapper.eq("user_id", userId);
        wrapper.between("create_time", dayStartTime, dayEndTime);
        wrapper.groupBy("type");
        List<PointsRecord> list = this.list(wrapper);
        if (CollUtils.isEmpty(list)) {
            return CollUtils.emptyList();
        }

        // 3.封装vo返回
        ArrayList<PointsStatisticsVO> voList = new ArrayList<>();
        for (PointsRecord r : list) {
            PointsStatisticsVO vo = new PointsStatisticsVO();
            vo.setType(r.getType().getDesc());
            vo.setMaxPoints(r.getType().getMaxPoints());
            vo.setPoints(r.getPoints());
            voList.add(vo);
        }

        return voList;
    }
}




